/*
 * Copyright (C) 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.codemirror2_gwt.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Command;

/**
 * Simple builder that allows users to configure various codemirror options.
 *
 * @author Nikhil Singhal
 */
public final class CodeMirrorConfig extends JavaScriptObject {

  public static native CodeMirrorConfig makeBuilder() /*-{
    return {};
  }-*/;

  protected CodeMirrorConfig() {}

  /**
   * Binds the specified command to the given key combination (e.g. "Ctrl-A)".
   */
  public native CodeMirrorConfig addShortcut(String keys, Command command) /*-{
    if (!this['extraKeys']) {
      this['extraKeys'] = {};
    }
    this['extraKeys'][keys] = $entry(function() {
      command.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * Configures whether the editor should re-indent the current line when a character is typed that
   * might change its proper indentation (only works if the mode supports indentation).
   * Default is true.
   */
  public native CodeMirrorConfig setElectricChars(boolean electric) /*-{
    this['electricChars'] = electric;
    return this;
  }-*/;

  /**
   * At which number to start counting lines. Default is 1.
   */
  public native CodeMirrorConfig setFirstLineNumber(int first) /*-{
    this['firstLineNumber'] = first;
    return this;
  }-*/;

  /**
   * How many spaces a block (whatever that means in the edited language) should be indented.
   * The default is 2.
   */
  public native CodeMirrorConfig setIndentUnit(int indentUnit) /*-{
    this['indentUnit'] = indentUnit;
    return this;
  }-*/;

  /**
   * Whether, when indenting, the first N*8 spaces should be replaced by N tabs. Default is false.
   */
  public native CodeMirrorConfig setIndentWithTabs(boolean useTabs) /*-{
    this['indentWithTabs'] = useTabs;
    return this;
  }-*/;

  /**
   * Configures the keymap to use. The default is "default".
   */
  public native CodeMirrorConfig setKeyMap(String keyMapName) /*-{
    this['keyMap'] = keyMapName;
    return this;
  }-*/;

  /**
   * Determines whether CodeMirror should scroll or wrap for long lines.
   * Default is false (scroll).
   */
  public native CodeMirrorConfig setLineWrapping(boolean lineWrapping) /*-{
    this['lineWrapping'] = lineWrapping;
    return this;
  }-*/;

  /**
   * Determines whether brackets are matched whenever the cursor is moved next to a bracket.
   */
  public native CodeMirrorConfig setMatchBrackets(boolean matchBrackets) /*-{
    this['matchBrackets'] = matchBrackets;
    return this;
  }-*/;

  /**
   * Sets the mode to use. When not given, this will default to the first mode that was loaded. It
   * should be a string, which either simply names the mode or a MIME type associated with the mode.
   */
  public native CodeMirrorConfig setMode(String mode) /*-{
    this['mode'] = mode;
    return this;
  }-*/;

  /**
   * The given function will be called whenever the editor is unfocused.
   */
  public native CodeMirrorConfig setOnBlur(Command blurHandler) /*-{
    this['onBlur'] = $entry(function() {
      blurHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * When given, this function will be called every time the content of the editor is changed.
   */
  @Deprecated
  public native CodeMirrorConfig setOnChange(Command changeHandler) /*-{
    this['onChange'] = $entry(function(editorInstance) {
      changeHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * When given, this function will be called every time the content of the editor is changed.
   */
  public native CodeMirrorConfig setOnChange(TextChangeHandler changeHandler) /*-{
    this['onChange'] = $entry(function(editorInstance, change) {
      changeHandler.
          @com.google.codemirror2_gwt.client.TextChangeHandler::onTextChange(Lcom/google/codemirror2_gwt/client/TextChange;)
            (change);
    });
    return this;
  }-*/;

  /**
   * Like {@link #setOnChange(Command)}, but will also be called when the cursor moves without any
   * changes being made.
   */
  public native CodeMirrorConfig setOnCursorActivity(Command cursorActivityHandler) /*-{
    this['onCursorActivity'] = $entry(function(editorInstance) {
      cursorActivityHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * The given function will be called whenever the editor is focused.
   */
  public native CodeMirrorConfig setOnFocus(Command focusHandler) /*-{
    this['onFocus'] = $entry(function() {
      focusHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * When given, will be called whenever the editor gutter (the line-number area) is clicked. Will
   * be given the (zero-based) number of the line that was clicked as an argument.
   */
  public native CodeMirrorConfig setOnGutterClick(GutterClickHandler gutterClickHandler) /*-{
    this['onGutterClick'] = $entry(function(editorInstance, lineNumber) {
      gutterClickHandler.@com.google.codemirror2_gwt.client.GutterClickHandler::onClick(I)(lineNumber);
    });
    return this;
  }-*/;

  /**
   * The given function will be called whenever editor's content has been fully highlighted.
   */
  public native CodeMirrorConfig setOnHighlightComplete(Command highlightHandler) /*-{
    this['onHighlightComplete'] = $entry(function(editorInstance) {
      highlightHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * This provides a rather low-level hook into CodeMirror's key handling. If provided, this
   * function will be called on every keydown and keypress event that CodeMirror captures. It will
   * be passed the key event as an argument. This key event is pretty much the raw key event, except
   * that a stop() method is always added to it. This function can inspect the key event, and handle
   * it if it wants to. It may return true to tell CodeMirror to ignore the event. Be wary that, on
   * some browsers, stopping a keydown does not stop the keypress from firing, whereas on others it
   * does. If you respond to an event, you should probably inspect its type property and only do
   * something when it is keydown (or keypress for actions that need character data).
   */
  public native CodeMirrorConfig setOnKeyEvent(KeyEventHandler keyEventHandler) /*-{
    this['onKeyEvent'] = function(editorInstance, e) {
      return keyEventHandler.
        @com.google.codemirror2_gwt.client.KeyEventHandler::onKeyEvent(Lcom/google/gwt/dom/client/NativeEvent;)
        (e);
    };
    return this;
  }-*/;

  /**
   * The given function will be called whenever the editor is scrolled.
   */
  public native CodeMirrorConfig setOnScroll(Command scrollHandler) /*-{
    this['onScroll'] = $entry(function(editorInstance) {
      scrollHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * The given function will be called whenever CodeMirror updates its DOM display.
   */
  public native CodeMirrorConfig setOnUpdate(Command updateHandler) /*-{
    this['onUpdate'] = $entry(function(editorInstance) {
      updateHandler.@com.google.gwt.user.client.Command::execute()();
    });
    return this;
  }-*/;

  /**
   * Indicates how quickly CodeMirror should poll its input
   * textarea for changes. Most input is captured by events, but some
   * things, like IME input on some browsers, doesn't generate events
   * that allow CodeMirror to properly detect it. Thus, it polls.
   * Default is 100 milliseconds.
   */
  public native CodeMirrorConfig setPollInterval(int pollInterval) /*-{
    this['pollInterval'] = pollInterval;
    return this;
  }-*/;

  /**
   * This disables editing of the editor content by the user. (Changes through API functions will
   * still be possible.)
   */
  public native CodeMirrorConfig setReadOnly(boolean readOnly) /*-{
    this['readOnly'] = readOnly;
    return this;
  }-*/;

  /**
   * Can be used to force a 'gutter' (empty space on the left of the editor) to be shown even when
   * no line numbers are active. This is useful for setting markers.
   */
  public native CodeMirrorConfig setShowGutter(boolean gutter) /*-{
    this['gutter'] = gutter;
    return this;
  }-*/;

  /**
   * Whether to show line numbers to the left of the editor.
   */
  public native CodeMirrorConfig setShowLineNumbers(boolean showLineNumbers) /*-{
    this['lineNumbers'] = showLineNumbers;
    return this;
  }-*/;

  /**
   * Determines whether new lines are indented when the enter key is pressed.
   * Default is true.
   */
  public native CodeMirrorConfig setSmartIndent(boolean smartIndent) /*-{
    this['smartIndent'] = smartIndent;
    return this;
  }-*/;

  /**
   * The tab index to assign to the editor. If not given, no tab index will be assigned.
   */
  public native CodeMirrorConfig setTabIndex(int tabIndex) /*-{
    this['tabindex'] = tabIndex;
    return this;
  }-*/;

  /**
   * How many spaces are produced by tab key.
   * The default is 4.
   */
  public native CodeMirrorConfig setTabSize(int tabSize) /*-{
    this['tabSize'] = tabSize;
    return this;
  }-*/;

  /**
   * The theme to style the editor with. You must make sure the CSS file defining the corresponding
   * .cm-s-[name] styles is loaded (see the theme directory in the distribution).
   */
  public native CodeMirrorConfig setTheme(String theme) /*-{
    this['theme'] = theme;
    return this;
  }-*/;

  /**
   * The maximum number of undo levels that the editor stores. Defaults to 40.
   */
  public native CodeMirrorConfig setUndoDepth(int depth) /*-{
    this['undoDepth'] = depth;
    return this;
  }-*/;

  /**
   * Sets the starting value of the editor.
   */
  public native CodeMirrorConfig setValue(String value) /*-/*-{
    this['value'] = value;
    return this;
  }-*/;

  /**
   * Highlighting is done by a pseudo background-thread that will work for some time, and then use
   * timeout to sleep for workDelay milliseconds. The default is 300 ms.
   */
  public native CodeMirrorConfig setWorkDelay(int workDelay) /*-{
    this['workDelay'] = workDelay;
    return this;
  }-*/;

  /**
   * Highlighting is done by a pseudo background-thread that will work for workTime milliseconds.
   * The default is 200 ms.
   */
  public native CodeMirrorConfig setWorkTime(int workTime) /*-{
    this['workTime'] = workTime;
    return this;
  }-*/;
}
